package com.wswy.wzcx.widget.home;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.SystemClock;
import android.support.v4.util.SparseArrayCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.NestedScrollView;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;


public class StickHeadScrollView extends NestedScrollView {

    private static final String TAG = "StickHeadScrollView";

    public StickHeadScrollView(Context context) {
        this(context,null);
    }

    public StickHeadScrollView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public StickHeadScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        final float ppi = getResources().getDisplayMetrics().density * 160.0f;
        mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
            * 39.37f // inch/meter
            * ppi
            * 0.84f; // look and feel tuning

        flingAnimator = new ValueAnimator();
        flingAnimator.setInterpolator(new DecelerateInterpolator());
        flingAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Object animatedValue = animation.getAnimatedValue();

                if (animatedValue instanceof Integer){
                    scrollTo(0,((Integer) animatedValue));
                }

            }
        });


    }

    private int headHeight=0;

    private float mPhysicalCoeff;

    private float mFlingFriction = ViewConfiguration.getScrollFriction();

    private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
    private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)



    private ValueAnimator flingAnimator;

    private SparseArrayCompat<Boolean> rvListenerStatus = new SparseArrayCompat<>(4);


    private long lastFlingTime;
    private int lastFlingDuration;
    private OnNestedPreScrollNotify onNestedNotify;


    private RecyclerView currRecyclerView;

    public interface OnNestedPreScrollNotify{
        void onNested(int scrollY,int topHeight);
    }

    public void setOnNestedNotify(
        OnNestedPreScrollNotify onNestedNotify) {
        this.onNestedNotify = onNestedNotify;

    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (onNestedNotify != null){
            onNestedNotify.onNested(t,headHeight);
        }
    }

    public void resetHeight(final View tabLayout, final View nestedContent) {

        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
                ViewGroup.LayoutParams layoutParams = nestedContent.getLayoutParams();
                layoutParams.height = getHeight()-getPaddingTop()-getPaddingBottom() - tabLayout.getHeight();

                headHeight = tabLayout.getTop();
                nestedContent.setLayoutParams(layoutParams);
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN){
            flingAnimator.cancel();
        }

        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {

        if (target instanceof RecyclerView){
          currRecyclerView = (RecyclerView) target;
            if (!rvListenerStatus.get(target.hashCode(),false)){
                ((RecyclerView) target).addOnScrollListener(rvOnScrollListener);
                rvListenerStatus.put(target.hashCode(),true);
            }
        }

        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }


    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {


        if (!dispatchNestedPreScroll(dx, dy, consumed, null)) {
            //嵌套滑动代码
            int sy = getScrollY();

            boolean hiddenTop = dy > 0 && sy < headHeight;
            boolean showTop = dy < 0 && getScrollY() > 0 && !canScrollVertically(-1);



            //Log.e(TAG, "onNestedPreScroll --> dy:"+dy+" sy:"+sy+"   "+headHeight+"  "+hiddenTop+"  "+showTop);

            if (hiddenTop || showTop) {

                int offsetY = dy;
                if (hiddenTop){

                    if (sy+dy > headHeight){
                        offsetY = headHeight-sy-dy;
                    }
                }

                scrollBy(0, offsetY);
                consumed[1] = offsetY;
            }
        }
    }


    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        //Log.e(TAG, "onNestedPreFling --> "+getScrollY()+"  "+headHeight+"  "+velocityY+ target);
      if (getScrollY() >= headHeight) {
        return false;
      }


        //Log.e(TAG, "onNestedPreFling --> "+getSplineFlingDistance(velocityY)+"   "+getSplineFlingDuration(velocityY));

//      if (velocityY > 0){
//          double offset = getSplineFlingDistance(velocityY)- (headHeight-getScrollY());
//          if (offset > 0){
//              return false;
//          }
//
//      }



        fling((int) velocityY);

        return true;
    }




    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {

        //Log.e(TAG, "onNestedFling --> "+velocityY+"   "+getScrollY());
        lastFlingTime = 0;
        lastFlingDuration = 0;
        if (target instanceof RecyclerView) {

            RecyclerView rv = ((RecyclerView) target);

            flingAnimator.cancel();
            double distance = getSplineFlingDistance(velocityY);
            int duration = getSplineFlingDuration(velocityY);

            //Log.e(TAG, "onNestedFling --> distance:"+distance+"  duration: "+duration);

            if (velocityY < 0) {
                lastFlingDuration = duration;
                lastFlingTime = SystemClock.elapsedRealtime();
               // Log.e(TAG, "onNestedFling --> "+getScrollY()+"    "+(getScrollY() - (int) (distance - rv.computeVerticalScrollOffset()))) ;

                flingAnimator.setIntValues(getScrollY(), getScrollY() - (int)(distance - rv.computeVerticalScrollOffset() ) );
            }

        }

        return super.onNestedFling(target, velocityX, velocityY, consumed);
    }

    private RecyclerView.OnScrollListener rvOnScrollListener=new OnScrollListener() {


        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (newState == RecyclerView.SCROLL_STATE_IDLE && recyclerView.computeVerticalScrollOffset() == 0){


                if (lastFlingDuration > 0 && lastFlingTime > 0){

                    int d =  lastFlingDuration - (int)(SystemClock.elapsedRealtime() - lastFlingTime) ;

                    if (d > 0){
                        flingAnimator.setDuration(d);
                        flingAnimator.start();
                    }

                }

                lastFlingDuration = 0;
                lastFlingTime = 0;

            }
        }

    };


    public void scrollTop(){
      if (currRecyclerView != null){
          currRecyclerView.stopScroll();
          currRecyclerView.scrollToPosition(0);
      }
        stopNestedScroll(ViewCompat.TYPE_NON_TOUCH);
        flingAnimator.cancel();
        flingAnimator.setDuration(200);
        flingAnimator.setIntValues(getScrollY(),0);
        flingAnimator.start();
    }


    private double getSplineDeceleration(float velocity) {
        return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
    }

    private double getSplineFlingDistance(float velocity) {
        final double l = getSplineDeceleration(velocity);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
    }

    /* Returns the duration, expressed in milliseconds */
    private int getSplineFlingDuration(float velocity) {
        final double l = getSplineDeceleration(velocity);
        final double decelMinusOne = DECELERATION_RATE - 1.0;
        return (int) (1000.0 * Math.exp(l / decelMinusOne));
    }

}